package com.cacheserverdeploy.algorithm;

import java.util.ArrayList;
import java.util.List;

import com.cacheserverdeploy.node.ConsumeNode;
import com.cacheserverdeploy.node.NetworkNode;

public class PSO {

//	private int m时段数;
	private int numofStation;// 站点数
	private int M;//种群个数
	private int Kmax;//迭代次数
	

	public List<Integer> PSOAlgorithm(NetworkNode[] nodes, ConsumeNode[] consumeNodes) {		
		double Wmax = 0.9; // W为权重系数
		double Wmin = 0.4;
		double c1 = 2;
		double c2 = 2; // c1,c2为学习因子，用来调节飞行步长
		double Vmax = 600.0; // Vmax为最大飞行速度
		

		double[][] A = new double[M][numofStation]; // A为随机数组
		int[][] G = new int[M][numofStation]; // G存储M组粒子T个时段的位置
		double[][] V = new double[M][numofStation]; // V存储M组粒子T个时段的速度
		double c = c1 + c2;
		double x = 2 / (Math.abs(2 - c - Math.sqrt(c * c - 4 * c)));
		// 生成随机数组 A

		int i, j;
		for (j = 0; j < M; j++)			
				for (i = 0; i < numofStation; i++)
					A[j][i] = Math.random();
			

		// 初始化粒子群位置和速度
		for (j = 0; j < M; j++) {
				for (i = 0; i < numofStation; i++) {
					if (A[j][i] > 0.5)
						V[j ][i] = A[j ][i] * Vmax;
					else
						V[j][i] = -A[j][i] * Vmax;										
					if (Math.random() < (1 / (1 + Math.pow(Math.E, -V[j][i]))))
							G[j][i] = 1;
					else
							G[j ][i] = 0;					
				}
			
		}

		// 粒子初始值出来之后，根据站点之间的停与不停的关系，获得时间关系表

		int K = 1;
		double[] Fjk = new double[M]; // Fjk存储第k次迭代时粒子群粒子的适应度
		double[] FPjbest = new double[M]; // FPjbest存储粒子群自身极小值所对应的适应度
		int[][] Pjbest = new int[M][numofStation]; // Pjbest存储粒子群自身极小值
		int[][] Gbest = new int[1][numofStation]; // Gbest存储粒子群当前最优值
		double FGbest = 1000000; // FGbest存储粒子群当前最优值所对应的适应度
		double rand1; // rand1,rand2是在分布在(0，1)之间的随机数
		double rand2;

		int[][] state_j = new int[1][numofStation]; // 存储一个粒子的
		do {
			if (K == 1)// K=1时第一次迭代，对粒子群进行初始化，粒子当前个体极值设为初始化时候的值，粒子群体全局极值为初始化粒子群体最优值
			{
				for (j = 0; j < M; j++) {// 不同的粒子
						for (i = 0; i < numofStation; i++){
							state_j[0][i] = G[j][i];
						}

					double Q1 = 0;

					try {						
						Q1 = MinTime(state_j, nodes, consumeNodes);
						
					} catch (Exception e1) {
						System.out.println("shit，有出错了!");
						e1.printStackTrace();
					}
					Fjk[j] = Q1;
				}

				for (j = 0; j < M; j++)
						for (i = 0; i < numofStation; i++)
							Pjbest[j][i] = G[j][i];
				for (j = 0; j < M; j++)
					FPjbest[j] = Fjk[j];
				
					for (i = 0; i < numofStation; i++)
						Gbest[0][i] = Pjbest[0][i];
				FGbest = FPjbest[0];

				for (j = 0; j < M; j++) {
					if (FPjbest[j] < FGbest) {
							for (i = 0; i < numofStation; i++)
								Gbest[0][i] = Pjbest[j][i];
						FGbest = FPjbest[j];
					}
				}
			}

			else// K!=1时对粒子的速度及位置进行更新，这个更新是不是要用到nodes
			{
				
			for (j = 0; j < M; j++) {//种群数量
					 for (i = 0; i < numofStation; i++) {
					 // ***************************
					 // ***************************
					 rand1 = Math.random();
					 rand2 = Math.random();
					 // 速度更新
					 V[j ][i] = x * ((Wmax - (Wmax - Wmin) * K / Kmax) * V[j][i]
					 + c1 * rand1 * (Pjbest[j][i] - G[j][i])
					 + c2 * rand2 * (Gbest[0][i] - G[j][i]));
					 if (V[j][i] > Vmax)
					     V[j][i] = Vmax;
					 if (V[j][i] < (-Vmax))
					     V[j][i] = -Vmax;
					
					 double r = Math.random();
					 // 位置更新
					 if ((V[j][i] < 0)&& (r <= (1 - 2 / (1 + Math.pow(Math.E, -V[j][i])))))
					 G[j][i] = 0;
					 else if ((V[j][i] > 0)&& (r <= (-1 + 2 / (1 + Math.pow(Math.E, -V[j ][i])))))
					 G[j][i] = 1;
					
					 }
			 }																
		

				// *************************************************

				// **************************************************************************************
				/*
				 * 判断是否满足要求，不然修改粒子状态
				 */

				// ***********************************************************************************

				for (j = 0; j < M; j++)// 求第k次迭代各粒子的适应度
				{
						for (i = 0; i < numofStation; i++)
							state_j[0][i] = G[j][i];
					

					/*********************** 适应度函数，待修正 ************************/
					
					double Q2 = 0;

					try {
							// 适应度函数
						int m=0;
						for (int ls : state_j[0]) {
							m+=ls;
						}
						if (m==0) {
							state_j[0][(int)Math.random()]=1;
						}
						Q2 = MinTime(state_j, nodes, consumeNodes);
						
					} catch (Exception e1) {
						System.out.println("shit，有出错了!");
						e1.printStackTrace();
					}
					Fjk[j] = Q2;
				}
				for (j = 0; j < M; j++)// 求各粒子的个体极值
				{
					if (Fjk[j] < FPjbest[j]) {
							for (i = 0; i < numofStation; i++)
								Pjbest[j][i] = G[j][i];
							FPjbest[j] = Fjk[j];						
					}
				}

				for (j = 0; j < M; j++)// 求粒子群体的全局极值
				{
					if (FPjbest[j] < FGbest) {
							for (i = 0; i < numofStation; i++)
								Gbest[0][i] = Pjbest[j][i];
						FGbest = FPjbest[j];
					}
				}

				// 输出当次迭代的最小耗流量
				// System.out.println(FGbest);
			}						
				K++;												
		}while(K<=Kmax);

	// 下面输出最优解
		List<Integer> bestSeverPosition=new ArrayList<>();
		for (int sever : Gbest[0]) {
			bestSeverPosition.add(sever);
		}
		
		return bestSeverPosition;
		
//	System.out.println(MinTime(Gbest,nodes,consumeNodes));
	
	
}

	public double MinTime(int[][] state_j, NetworkNode[] nodes, ConsumeNode[] consumeNodes) {
		// TODO Auto-generated method stub
		List<Integer> severlocation = new ArrayList<>();
		for (int i = 0; i < state_j.length; i++) {
			for (int j = 0; j < state_j[0].length; j++) {
				if (state_j[i][j] == 1) {
					severlocation.add(j);
//					nodes[j].setLocatedServer(true);
				}

			}
		}
		ThirdStepCopy step3 = new ThirdStepCopy();
		int price = step3.adjust(severlocation, nodes, consumeNodes);

		return price;
	}


	public int getNumofStation() {
		return numofStation;
	}

	public void setNumofStation(int numofStation) {
		this.numofStation = numofStation;
	}

	public int getM() {
		return M;
	}

	public void setM(int m) {
		M = m;
	}

	public int getKmax() {
		return Kmax;
	}

	public void setKmax(int kmax) {
		Kmax = kmax;
	}

}
